package service

import (
	"context"
	"go.uber.org/zap"
	"jk-time/webook/internal/domain"
	"jk-time/webook/internal/repository"
	"time"
)

//go:generate mockgen -source=./job.go -package=mocks -destination=mocks/job.mock.go JobService
type JobService interface {
	//Preempt抢占
	Preempt(ctx context.Context) (domain.Job, error)
	Release(ctx context.Context, id int64) error
	ResetNextTime(ctx context.Context, j domain.Job) error
	AddJob(ctx context.Context, j domain.Job) error
}
type cronJobService struct {
	repo            repository.JobRepository
	refreshInterval time.Duration
}

func NewCronJobService(repo repository.JobRepository) JobService {
	return &cronJobService{repo: repo}
}

func (p *cronJobService) Preempt(ctx context.Context) (domain.Job, error) {
	j, err := p.repo.Preempt(ctx)
	if err != nil {
		return domain.Job{}, err
	}

	ticker := time.NewTicker(p.refreshInterval)
	go func() {
		for range ticker.C {
			//续约
			p.refresh(j.Id)
		}
	}()
	//抢占之后，一直抢占着吗？
	j.CancelFunc = func() error {
		ticker.Stop()
		ctx, cancel := context.WithTimeout(context.Background(), time.Second)
		defer cancel()
		//释放
		return p.repo.Release(ctx, j.Id)
	}
	return j, nil
}
func (p *cronJobService) refresh(id int64) {
	//续约失败，处于running状态，且更新时间在3min前
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	err := p.repo.UpdateUtime(ctx, id)
	cancel()

	if err != nil {
		zap.L().Error("mysql续约失败",
			zap.Error(err),
			zap.Int64("jid", id))
	}
}
func (p *cronJobService) Release(ctx context.Context, id int64) error {
	return p.repo.Release(ctx, id)
}
func (p *cronJobService) ResetNextTime(ctx context.Context, j domain.Job) error {
	next := j.Next()
	if next.IsZero() {
		//没有下一次
		return p.repo.Stop(ctx, j.Id)
	}
	return p.repo.UpdateNextTime(ctx, j.Id)
}
func (p *cronJobService) AddJob(ctx context.Context, j domain.Job) error {
	j.NextTime = j.Next()
	return p.repo.AddJob(ctx, j)
}
